//********************************************************************************************************
// Product Name: MapWindow.dll Alpha
// Description:  The core libraries for the MapWindow 6.0 project.
//
//********************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either expressed or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
//
// The Original Code is from MapWindow.dll version 6.0
//
// The Initial Developer of this Original Code is Ted Dunsford. January 2008
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
//
//********************************************************************************************************
using System;
using System.Collections.Generic;
using System.Text;
using MapWindow.Data;
using MapWindow.Main;
using MapWindow.Geometries;
namespace MapWindow.Drawing
{
    /// <summary>
    /// Creates a new Grid that contains a surface, sidewalls and a bottom.
    /// </summary>
    public class Grid: IRenderable
    {
        /// <summary>
        /// Occurs immediately after the visible parameter has been adjusted.
        /// </summary>
        public event EventHandler VisibleChanged;
       
        GridSurface _surface;
        GridBottom _bottom = null;
        GridWalls _walls = null;
        IEnvelope _extents;
        bool _isVisible = true; // by default all the grid components are visible.


        #region Constructors
        
        /// <summary>
        /// Creates a new instance of a 3-D grid, complete with a surface, walls and a bottom.
        /// </summary>
        /// <param name="Raster">The raster to obtain values from in order to build a 3D grid with sides and a bottom</param>
        /// <param name="ProgressHandler">An IProgress for receiving progress messages.</param>
        public Grid(IRaster Raster, IProgressHandler ProgressHandler)
        {
            // The time consuming element of grid creation is the surface
            _surface = new GridSurface(Raster, ProgressHandler);

            // By default, the program will look for a texture file with the same name as the raster and .bmp
            string texturefile = System.IO.Path.ChangeExtension(Raster.Filename,".bmp");
            if(System.IO.File.Exists(texturefile))
            {
                _surface.TextureLayer = new TextureLayer(texturefile);
            }

            _extents = Raster.Bounds.Envelope;
        }


        #endregion

        /// <summary>
        /// This assumes that the rasterSymbolizer has been changed, which implies that the grid is no longer valid.
        /// </summary>
        public void Reset()
        {
            _surface.Reset();
        }

        #region IRenderable3D Members

       

        /// <summary>
        /// This simply instructs each of the components to draw themselves if they are visible.
        /// </summary>
        /// <param name="device">A Microsoft.DirectX.Direct3D.Device to draw to</param>
        public void Draw(IGraphics device)
        {
            Draw(device, null);
        }

        /// <summary>
        /// This simply instructs each of the components to draw themselves if they are visible.
        /// </summary>
        /// <param name="device">A Microsoft.DirectX.Direct3D.Device to draw to</param>
        /// <param name="progressHandler">Any valid implementation of the MapWindow.Main.IProgressHandler interface for recieving progress messages</param>
        public void Draw(IGraphics device, IProgressHandler progressHandler)
        {
            
            if (device == null)
            {
                throw new ArgumentException("The specified device could not be cast to a Microsoft.DirectX.Direct3D.Device");
            }
            // This controls whether everything is visible or not.  If it is not visible, simply don't draw it.
            if (_isVisible == false) return;
            // World transforms have a nasty habbit of being 0?
            if (device.Transforms.World == null) device.Transforms.World = device.Factory.IdentityMatrix;
            IMatrix oldMatrix = device.Transforms.World;
            
            

            if(_surface != null)_surface.Draw(device);
            if(_walls != null)_walls.Draw(device);
            if(_bottom != null)_bottom.Draw(device);

            device.Transforms.World = oldMatrix;
        }


        /// <summary>
        /// Disposes all the elements of the grid
        /// </summary>
        public void Dispose()
        {
            _bottom.Dispose();
            _walls.Dispose();
            _surface.Dispose();
        }

        /// <summary>
        /// Gets the 2D envelope for the grid.
        /// </summary>
        public MapWindow.Geometries.IEnvelope Envelope
        {
            get { return _extents; }
        }

        /// <summary>
        /// Gets or sets whether the entire grid is visible or not.
        /// </summary>
        public bool IsVisible
        {
            get { return _isVisible; }
            set { _isVisible = value; }
        }

        #endregion

        #region Draw Events

        /// <summary>
        /// Occurs when the Draw method is called and provides the option to cancel the event before anything is actually drawn.
        /// </summary>
        public virtual event EventHandler<DrawCancel> BeforeDrawing;

        /// <summary>
        /// Fires the event that occurs before drawing to a directX map
        /// </summary>
        /// <param name="device">A DirectX.Direct3D.Device that will be drawn to</param>
        /// <returns>Boolean, that if true should cancel the draw event.</returns>
        protected virtual bool OnBeforeDrawing(IGraphics device)
        {
            if (BeforeDrawing == null) return false;
            DrawCancel e = new DrawCancel(device);
            BeforeDrawing(this, e);
            return e.Cancel;
        }


        /// <summary>
        /// Occurs after the contents of this MapLayerCollection have been rendered to the Microsoft.DirectX.Direct3D.Device
        /// </summary>
        public virtual event EventHandler<DrawCompleted> AfterDrawing;

        /// <summary>
        /// Fires an event when we are done with the drawing code, whether the drawing was successful, cancelled, or threw an exception.
        /// </summary>
        /// <param name="device">A DirectX.Direct3D.Device that rendering took place on</param>
        /// <param name="cancelled">If true, the event was cancelled normally</param>
        /// <param name="ex">An Exception in the event that this was an error.  This will normally be null.</param>
        protected virtual void OnAfterDrawing(IGraphics device, bool cancelled, Exception ex)
        {
            if (AfterDrawing == null) return;
            DrawCompleted e;
            if (ex == null)
            {
                e = new DrawCompleted(device, cancelled);
            }
            else
            {
                e = new DrawCompleted(device, ex);
            }
            AfterDrawing(this, e);
        }


        #endregion

        /// <summary>
        /// Fires the Visible Changed event
        /// </summary>
        protected virtual void OnVisibleChanged()
        {
            VisibleChanged(this, new EventArgs());
        }
    }
}
